
package com.gitee.jmash.rbac.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import com.crenjoy.proto.utils.TypeUtil;
import com.gitee.jmash.common.utils.UUIDUtil;
import com.gitee.jmash.core.orm.DtoPage;
import com.gitee.jmash.core.orm.DtoTotal;
import com.gitee.jmash.core.orm.jpa.BaseDao;
import com.gitee.jmash.core.orm.jpa.SqlBuilder;
import com.gitee.jmash.core.orm.jpa.TenantEntityManager;
import com.gitee.jmash.rbac.entity.UserEntity;
import jakarta.persistence.Query;
import jmash.rbac.protobuf.UserReq;

/**
 * User实体的Dao层（使用JPA实现）.
 *
 * @author <a href="mailto:service@crenjoy.com">crenjoy</a>
 */
public class UserDao extends BaseDao<UserEntity, UUID> {

  public UserDao() {
    super();
  }

  public UserDao(TenantEntityManager tem) {
    super(tem);
  }

  /** 查询directoryId可选列表. */
  @SuppressWarnings("unchecked")
  public List<String> findDirectoryIds() {
    String sql =
        "select s.directoryId from UserEntity s where s.directoryId <> '' group by s.directoryId ";
    Query query = this.getEntityManager().createQuery(sql);
    return query.getResultList();
  }

  /** 查询用户. */
  public UserEntity findByUserName(String directoryId, String userName) {
    if (StringUtils.isBlank(directoryId) || StringUtils.isBlank(userName)) {
      return null;
    }
    UserEntity entity = null;
    if (entity == null && userName.indexOf("@") != -1) {
      entity = findByUserName(directoryId, userName, "email");
    }
    if (entity == null && StringUtils.isNumeric(userName)) {
      entity = findByUserName(directoryId, userName, "mobilePhone");
    }
    if (entity == null) {
      entity = findByUserName(directoryId, userName, "loginName");
    }
    return entity;
  }
  
  /** 查询组织用户. */
  public UserEntity findUserByUnifiedId(String unifiedId) {
    String sql ="select s from UserEntity s where  s.unifiedId=?1 ";
    return this.findSingle(sql, unifiedId);
  }

  /** 查询用户. */
  public UserEntity findByUserName(String directoryId, String userName, String fieldName) {
    String sql = String.format("select s from UserEntity s where  s.directoryId=?1 and s.%s=?2  ",
        fieldName);
    return this.findSingle(sql, directoryId, userName);
  }

  /**
   * 综合查询.
   */
  public List<UserEntity> findListByReq(UserReq req) {
    SqlBuilder sqlBuilder = createSql(req);
    String query = sqlBuilder.getQuerySql("select s ");
    return this.findListByParams(query, sqlBuilder.getParams());
  }

  /**
   * 综合查询Page.
   */
  public DtoPage<UserEntity, DtoTotal> findPageByReq(UserReq req) {
    SqlBuilder sqlBuilder = createSql(req);
    String query = sqlBuilder.getQuerySql("select s ");
    String totalQuery = sqlBuilder.getTotalSql("select count(s) as totalSize ");
    return this.findDtoPageByParams(req.getCurPage(), req.getPageSize(), query, totalQuery,
        DtoTotal.class, sqlBuilder.getParams());
  }

  /** Create SQL By Req . */
  public SqlBuilder createSql(UserReq req) {
    StringBuilder sql = new StringBuilder(" from UserEntity s where 1=1  ");
    Map<String, Object> params = new HashMap<String, Object>();

    if (StringUtils.isNotBlank(req.getDirectoryId())) {
      sql.append(" and s.directoryId = :directoryId ");
      params.put("directoryId", req.getDirectoryId());
    }

    if (StringUtils.isNotBlank(req.getLoginName())) {
      sql.append(
          " and (s.loginName = :loginName or s.mobilePhone = :mobilePhone or s.email = :email or s.realName = :realName )");
      params.put("loginName", req.getLoginName());
      params.put("mobilePhone", req.getLoginName());
      params.put("email", req.getLoginName());
      params.put("realName", req.getLoginName());
    }

    if (!req.getShowDeleted()) {
      sql.append(" and s.deleted = :deleted ");
      params.put("deleted", false);
    }

    if (req.getHasUserStatus()) {
      sql.append(" and s.status = :userStatus ");
      params.put("userStatus", req.getUserStatus());
    }

    if (StringUtils.isNotBlank(req.getRoleCode())) {
      // 子查询结果较少,用in效率高.
      sql.append(
          " and s.userId in (select ur.userId from UsersRolesEntity ur, RoleEntity r where ur.roleId=r.roleId and r.roleCode = :roleCode ) ");
      params.put("roleCode", req.getRoleCode());
    }

    if (!TypeUtil.isEmpty(req.getDeptId())) {
      sql.append(
          " and s.userId in (select uj.userId from UsersJobsEntity uj where uj.deptId = :deptId )");
      params.put("deptId", UUIDUtil.fromString(req.getDeptId()));
    }

    if (StringUtils.isNotBlank(req.getJobCode())) {
      sql.append(
          " and s.userId in (select uj.userId from UsersJobsEntity uj, RoleEntity r where uj.jobId = r.roleId and r.roleCode = :jobCode )");
      params.put("jobCode", req.getJobCode());
    }

    if (StringUtils.isNotBlank(req.getJobId())) {
      sql.append(
          " and s.userId in (select uj.userId from UsersJobsEntity uj, RoleEntity r where uj.jobId = r.roleId and r.roleId = :jobId )");
      params.put("jobId", UUIDUtil.fromString(req.getJobId()));
    }

    if (!TypeUtil.isEmpty(req.getCreateBy())) {
      sql.append(" and s.createBy = :createBy ");
      params.put("createBy", req.getCreateBy());
    }

    if (req.getUserIdCount() > 0) {
      List<UUID> userIds = req.getUserIdList().stream().map(UUIDUtil::fromString).toList();
      sql.append(" and s.userId in (:userIds) ");
      params.put("userIds", userIds);
    }

    if(StringUtils.isNotBlank(req.getRealName())) {
      sql.append(" and s.realName = :realName ");
      params.put("realName", req.getRealName());
    }

    if(StringUtils.isNotBlank(req.getLikeNickName())) {
      sql.append(" and s.nickName like :nickName ");
      params.put("nickName", "%" + req.getLikeNickName() + "%");
    }

    String orderSql = " order by s.createTime desc ";
    if (StringUtils.isNotBlank(req.getOrderName())) {
      orderSql = String.format(" order by %s %s ", req.getOrderName(),
          req.getOrderAsc() ? " asc " : " desc ");
    }

    return SqlBuilder.build().setSql(sql).setParams(params).setOrderSql(orderSql);
  }
}
